/*
 * A simple ToDo Manager
 *
 * Copyright (c) 2011 Nosheen Zaza, Manuel Rebollo, Seyedsaeid Mahpeikar and
 * Wo Ke
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package todomanager.ui;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Calendar;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.prefs.Preferences;
import javax.swing.Action;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.text.StyledEditorKit;
import todomanager.model.TaskManager;
import todomanager.ui.tableview.TaskTableModel;

/**
 * This class all shared user actions, or actions what we expect
 * will become shared in future releases. That is, if there are
 * actions that need to be shared between, say a button and a menu item, this
 * class provides the needed actions, and ensures there is only one
 * copy of the required action. Note that this class does not hold "all" 
 * actions used in this application, we did that at first but then found out
 * that this is inconvenient in Java because of the way swing is designed. We
 * decided that it makes more sense to group together the view and it related 
 * action, since, then it will be clear which action is used by which component.
 * We also notices that this class was getting huge and hard to follow.
 *
 * Other than that, this class provides methods to get the current Locale, and
 * a reference to the main window, since most view components need references
 * to these two. <br/>
 * This class is a singleton for convenience. Use
 * {@code ActionControl.getInstance();} to get the only instance of this class.
 * 
 * @author Nosheen Zaza
 * @author Seyedsaeid Mahpeikar
 * @author Manuel Rebollo
 */
public class ActionControl {

    private static ActionControl actionControl;
    private Locale currentLocale;
    private ResourceBundle stringsBundle;
    private Preferences language, currentUserRoot;
    private AddTaskAction addTaskAction;
    private CreateTaskAction createTaskAction;
    private TasksTodayAction tasksTodayAction;
    private ExitAction exitAction;
    private Action copyAction;
    private Action cutAction;
    private Action pasteAction;
    private ToEnglishAction toEnglishAction;
    private ToKurdishAction toKurdishAction;
    private AboutAction aboutAction;
    private HowToUseAction howToUseAction;
    private ClassLoader loader;
    /**
     * The view controlled by this action control.
     */
    private MainWindow mainWindow;

    /**
     * Creates an instance of this class, and initializes its fields.
     */
    private ActionControl() {

        loader = this.getClass().getClassLoader();

        /*
         * Load the language used in the previous session, or the changed
         * language.
         */
        currentUserRoot = Preferences.userRoot();
        language = currentUserRoot.node("Group6.ToDoManager.preference.language");

        // If for some reason no preferences are found, the default is English
        if (language != null
                && language.get(
                "language", "ENGLISH").equals("KURDISH")) {
            currentLocale = new Locale("ku");
        } else {
            currentLocale = Locale.ENGLISH;
        }


        stringsBundle = ResourceBundle.getBundle("todomanager/ui/StringsBundle", currentLocale);

        toEnglishAction = new ToEnglishAction();
        toKurdishAction = new ToKurdishAction();

        addTaskAction = new AddTaskAction();
        createTaskAction = new CreateTaskAction();
        tasksTodayAction = new TasksTodayAction();
        exitAction = new ExitAction(stringsBundle.getString("exitItem"));

        copyAction = new StyledEditorKit.CopyAction();
        copyAction.putValue(Action.NAME, stringsBundle.getString("copy"));
        copyAction.putValue(Action.ACCELERATOR_KEY,
                KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));

        pasteAction = new StyledEditorKit.PasteAction();
        pasteAction.putValue(Action.NAME, stringsBundle.getString("paste"));
        pasteAction.putValue(Action.ACCELERATOR_KEY,
                KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK));

        cutAction = new StyledEditorKit.CutAction();
        cutAction.putValue(Action.NAME, stringsBundle.getString("cut"));
        cutAction.putValue(Action.ACCELERATOR_KEY,
                KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK));

        aboutAction = new AboutAction(stringsBundle.getString("aboutItem"));
        howToUseAction = new HowToUseAction(stringsBundle.getString("howTo"));
    }

    /**
     * Returns the only instance of this singleton class.
     * @return
     */
    public static ActionControl getInstance() {
        if (actionControl == null) {
            actionControl = new ActionControl();
        }
        return actionControl;
    }

    /**
     * Prevents cloning this singleton class.
     * @return Object
     * @throws CloneNotSupportedException
     */
    @Override
    public Object clone()
            throws CloneNotSupportedException {
        throw new CloneNotSupportedException();

    }

    /**
     * Triggers changing the interface language to English.
     */
    public class ToEnglishAction extends AbstractAction {

        /**
         * Creates an instance of this class.
         */
        public ToEnglishAction() {
            super(stringsBundle.getString("englishLanguage"));
        }

        /**
         * Triggers changing language to English
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            language.put("language", "ENGLSIH");

            JOptionPane.showMessageDialog(null,
                    stringsBundle.getString("langChange"));
        }
    }

    /**
     * Triggers changing the interface language to Arabic.
     */
    public class ToKurdishAction extends AbstractAction {

        /**
         * Creates an instance of this class.
         */
        public ToKurdishAction() {
            super(stringsBundle.getString("kurdishLanguage"));
        }

        /**
         * Triggers changing language to Arabic and commands GUI elements to
         * update themselves
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            language.put("language", "KURDISH");

            JOptionPane.showMessageDialog(null,
                    stringsBundle.getString("langChange"));
        }
    }

    /**
     * Add task action, issues a command to show an GUI element to allow the user
     * to enter a new task's information.
     */
    public class AddTaskAction extends AbstractAction {

        /**
         * Created a new instance of this class
         */
        public AddTaskAction() {
            super(stringsBundle.getString("add"));
            putValue(SHORT_DESCRIPTION, stringsBundle.getString("taskToolTip"));
            putValue(Action.MNEMONIC_KEY,
                    Integer.valueOf(stringsBundle.getString(
                    "addItemMnemonic").charAt(0)));
            putValue(Action.ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
        }

        /**
         * shows a dialog to allow the user to enter a task's information.
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            mainWindow.getAddTaskDialog().setVisible(true);
        }
    }

    /**
     * Triggers creating a new task according to given parameters
     */
    public class CreateTaskAction extends AbstractAction {

        /**
         * Creates a new instance of this class
         */
        public CreateTaskAction() {
            super(stringsBundle.getString("addCommand"));
        }

        /**
         * Commands the {@code TaskManager} to create a new task.
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            // Do not allow empty, or space only tasks to be added
            if (!mainWindow.getAddTaskDialog().getTaskTextArea().getText().trim().equals("")) {
                if (mainWindow.getAddTaskDialog().getDateChooser().getDate() == null) {
                    TaskManager.getInstance().addTask(
                            mainWindow.getAddTaskDialog().getTaskTextArea().getText(),
                            mainWindow.getAddTaskDialog().getCategoryComboBox().getSelectedItem().toString(),
                            mainWindow.getAddTaskDialog().getPriorityComboBox().getSelectedItem().toString());
                } else {
                    TaskManager.getInstance().addTask(
                            mainWindow.getAddTaskDialog().getTaskTextArea().getText(),
                            mainWindow.getAddTaskDialog().getCategoryComboBox().getSelectedItem().toString(),
                            mainWindow.getAddTaskDialog().getPriorityComboBox().getSelectedItem().toString(),
                            mainWindow.getAddTaskDialog().getDateChooser().getCalendar().get(Calendar.YEAR),
                            mainWindow.getAddTaskDialog().getDateChooser().getCalendar().get(Calendar.MONTH),
                            mainWindow.getAddTaskDialog().getDateChooser().getCalendar().get(Calendar.DATE));
                }

                // Empties the text box when this dialog box is closed
                mainWindow.getAddTaskDialog().getTaskTextArea().setText("");
                mainWindow.getAddTaskDialog().setVisible(false);

                // Updates the table to show the new task
                TaskTableModel ttm =
                        (TaskTableModel) mainWindow.getTaskTable().getModel();
                ttm.fireTableDataChanged();
            } else {
                JOptionPane.showMessageDialog(null, stringsBundle.getString("EmptyTask"));
            }
        }
    }

    /**
     * Shows today's tasks dialog box.
     */
    public class TasksTodayAction extends AbstractAction {

        /**
         * Creates an instance of this class.
         */
        public TasksTodayAction() {
            super(stringsBundle.getString("TodaysTasks"));
            putValue(Action.ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK));
        }

        /**
         * Shows today's tasks dialog box.
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            mainWindow.getTasksTodayDialog().setVisible(true);
        }
    }

    /**
     * Commands the application to exit and do some house keeping tasks.
     */
    public class ExitAction extends AbstractAction {

        /**
         * Created a new instance of this class.
         * @param text
         */
        public ExitAction(String text) {
            super(text);
            putValue(Action.ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK));
        }

        /**
         * Commands (@code MainWindow ) to close and do some house keeping tasks.
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            ActionControl.this.mainWindow.closeApplication();
        }
    }

    /**
     * Shows the About dialog
     */
    public class AboutAction extends AbstractAction {

        /**
         * Creates a new instance of this class.
         * @param text
         */
        public AboutAction(String text) {
            super(text);
        }

        /**
         * Shows the about dialog.
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            mainWindow.getAboutDialog().setVisible(true);
        }
    }

    /**
     * Shows the How to use dialog
     */
    public class HowToUseAction extends AbstractAction {

        /**
         * Creates a new instance of this class.
         * @param text
         */
        public HowToUseAction(String text) {
            super(text);
            putValue(Action.ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke("F1"));
        }

        /**
         * Shows the how to use dialog.
         * @param e
         */
        public void actionPerformed(ActionEvent e) {
            mainWindow.getHowToUseDialog().setVisible(true);
        }
    }

    /**
     * Returns an instance of {@code ToEnglishAction}
     * @return toEnAction
     */
    public ToEnglishAction getToEnglishAction() {
        return toEnglishAction;
    }

    /**
     * Returns an instance of {@code ToKurdishAction}
     * @return toArAction
     */
    public ToKurdishAction getToKurdishAction() {
        return toKurdishAction;
    }

    /**
     * Returns an instance of {@code AddTaskAction}
     * @return addTaskAction
     */
    public AddTaskAction getNewTaskAction() {
        return addTaskAction;
    }

    /**
     * Returns an instance of {@code CreateTaskAction}
     * @return createTaskAction
     */
    public CreateTaskAction getCreateTaskAction() {
        return createTaskAction;
    }

    /**
     * Returns an instance of {@code ExitAction}
     * @return exitAction
     */
    public ExitAction getExitAction() {
        return exitAction;
    }

    /**
     * Returns an instance of a copy {@code Action}
     * @return copyAction
     */
    public Action getCopyAction() {
        return copyAction;
    }

    /**
     *  Returns an instance of a copy {@code Action}
     * @return cutAction
     */
    public Action getCutAction() {
        return cutAction;
    }

    /**
     * Returns an instance of a paste {@code Action}
     * @return pasteAction
     */
    public Action getPasteAction() {
        return pasteAction;
    }

    /**
     * Returns an instance of an {@code AboutAction}
     * @return aboutAction
     */
    public AboutAction getAboutAction() {
        return aboutAction;
    }

    /**
     * Returns an instance of {@code HowToUseAction}
     * @return howToUseAction
     */
    public HowToUseAction getHowToUseAction() {
        return howToUseAction;
    }

    public TasksTodayAction getTasksTodayAction() {
        return tasksTodayAction;
    }

    /**
     * Adds a view to this Action Controller
     * @param mw
     */
    public void addView(MainWindow mw) {
        this.mainWindow = mw;
    }

    /**
     * Returns a strings bundle.
     * @return stringsBundle
     */
    public ResourceBundle getStringsBundle() {
        return stringsBundle;
    }

    public MainWindow getMainWindow() {
        return mainWindow;
    }

    /**
     * Returns the current Locale
     * @return currentLocale
     */
    public Locale getCurrentLocale() {
        return currentLocale;
    }
}
